package com.demo.rabbitmq.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.retry.ImmediateRequeueMessageRecoverer;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
public class RabbitMQConfig implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
        // RabbitTemplate，自动将对象序列化为JSON字符串，并将其发送到RabbitMQ
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());

        // ConfirmCallback 接口，消息发送到 Broker 后触发回调，确认消息是否到达 Broker 服务器，也就是只确认是否正确到达 Exchange
        rabbitTemplate.setConfirmCallback((CorrelationData correlationData, boolean ack, String cause) -> {
            log.info("ack: " + ack);
            log.info("cause: " + cause);
            // 生产者在发送消息时带上参数CorrelationData，回调接口CorrelationData才会有值
            if (correlationData != null) {
                log.info("correlationData: " + correlationData);
            }
        });

        // 配置文件设置mandatory=true代表强制发送，即使exchange找不到routingkey对应的队列也会尝试，如果失败则会回调ReturnCallback
        // RabbitMQ会调用Basic.Return命令将消息返回给生产者
        rabbitTemplate.setReturnsCallback((ReturnedMessage returned) -> {
            log.info("ReturnedMessage: " + returned);
            log.info("message: " + new String(returned.getMessage().getBody()));
        });
    }

    /**
     * 消息消费失败策略，默认策略是RejectAndDontRequeueRecoverer
     * 重试耗尽后，返回nack，消息重新入队
     * @return MessageRecoverer
     */
    @Bean
    @ConditionalOnProperty(name = "spring.rabbitmq.listener.simple.acknowledge-mode",havingValue = "auto")
    public MessageRecoverer messageRecoverer(){
        log.info("消费失败策略初始化");
        return new ImmediateRequeueMessageRecoverer();
    }
}
